package uni.stuttgart.openstreetmap;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.Process;

public class TileProvider extends HandlerThread{
	
	public static final int TILE_UPDATE = 0;
	
	public static final int CONNECT_TIMEOUT = 500; //Milliseconds
	public static final int READ_TIMEOUT = 500; //Milliseconds
	
	private static Handler handler;
	private static UserInterface ui;
	
	private static final class TileManagementHandler extends Handler{
		TileManagementHandler(Looper looper){
			super(looper);
		}
		
		@Override
		public void handleMessage(Message msg) {
			switch (msg.what){
			
			case TILE_UPDATE:
				try {
					TileProvider.tileUpdate(((MapTile)msg.obj));
				} catch (IOException e) {
					System.out.println("Download and save tile failed");
				}
				break;
			

			default:
				break;
			}
		}
	}
	
	public void cancelQueuedOperations(){
		handler.removeMessages(TILE_UPDATE);
	}
	
	public void requestTileUpdate(MapTile tile){
		Message msg = TileProvider.handler.obtainMessage(TILE_UPDATE, tile);
		TileProvider.handler.sendMessage(msg);
	}
	
	public TileProvider(UserInterface ui){
		super("TileProviderThread",Process.THREAD_PRIORITY_BACKGROUND);
		TileProvider.ui = ui;
		this.start();
		handler = new TileManagementHandler(this.getLooper());
	}
	
	private static void tileUpdate(MapTile tile) throws IOException{
		
		int x = tile.getX();
		int y = tile.getY();
		int z = tile.getZ();
		
		Bitmap tilePicture;
		File currentPictureDirectory = new File(ui.getExternalFilesDir(null).getAbsolutePath()+File.separator+"savedMapTiles"+File.separator+"height "+z+File.separator);
		
		if(!currentPictureDirectory.exists()){
			currentPictureDirectory.mkdirs();
		}
		
		File imageFile = new File(currentPictureDirectory,"x="+x+" y="+y+ " z="+z+".png");
		
		
		//check if imageFile available from local sd card
		if(!imageFile.exists()){
			//imageFile not on sd card we have to download it
			
			//http://tile.openstreetmap.org/9/269/176.png
			
			URL tileUrl = null;
			HttpURLConnection connection = null;
			InputStream pictureInputStream = null;
			ByteArrayOutputStream pictureOutputStream = null;
			FileOutputStream fileOutputStream = null;
			
			try {
				//download the map tile
				//System.out.println("Try to download tile x = "+x+" y= "+y+" z = "+z);
				tileUrl = new URL("http://tile.openstreetmap.org/"+z+"/"+x+"/"+y+".png");
				connection = (HttpURLConnection) tileUrl.openConnection();
				connection.setConnectTimeout(CONNECT_TIMEOUT);
				connection.setReadTimeout(READ_TIMEOUT);
				connection.connect();
				pictureInputStream = connection.getInputStream();
				tilePicture = BitmapFactory.decodeStream(pictureInputStream);
				
				//update the UserInterface
				ui.requestTileUpdate(new MapTile(x, y, z, tilePicture));
				
				//save tile as image file for future use
				pictureOutputStream = new ByteArrayOutputStream();
				tilePicture.compress(Bitmap.CompressFormat.PNG, 100, pictureOutputStream);
				imageFile.createNewFile();
				fileOutputStream = new FileOutputStream(imageFile);
				fileOutputStream.write(pictureOutputStream.toByteArray());
				
			} 
			finally{
				//close connection and file streams
				
				if(pictureInputStream!=null){
					pictureInputStream.close();
				}
				
				if(connection!=null){
					connection.disconnect();
				}
				
				if(pictureOutputStream!=null){
					pictureOutputStream.close();
				}
				
				if(fileOutputStream!=null){
					fileOutputStream.close();
				}
			}
		}
		else{
			//we are lucky imageFile is already on sd card
			
			//load tile from sd card
			tilePicture = BitmapFactory.decodeFile(imageFile.getAbsolutePath());
			
			//update the UserInterface
			ui.requestTileUpdate(new MapTile(x, y, z, tilePicture));
		}

	}
	

}
